package edu.hawaii.myisern.model;

import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import edu.hawaii.myisern.action.users.UserManager;
import edu.hawaii.myisern.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.collaborations.jaxb.Years;
import edu.hawaii.myisern.organizations.jaxb.AffiliatedResearchers;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.organizations.jaxb.ResearchKeywords;
import edu.hawaii.myisern.researchers.jaxb.Researcher;
import edu.hawaii.myisern.sanitycheck.SanityCheck;
import edu.hawaii.myisern.sanitycheck.SanityCheckErrorItem;
import edu.hawaii.myisern.xml.MyIsernXmlLoader;

/**
 * Calls different classes.
 * 
 * @author Michal Zielinski
 * @author John Hauge
 * 
 */
public class MyIsernModel {
  /** The singleton MyIsernModel instance. */
  private static MyIsernModel theInstance = new MyIsernModel();
  /** satisfies pmd */
  private final String home = "user.home";
  private static UserManager userManager = new UserManager();
  private static Logger logger = Logger.getLogger("edu.hawaii.myisern.Orange");
  
  /** contains the collaboration unique keys and its values. */
  public ConcurrentHashMap<String, Collaboration> collaborationMap;
  /** contains the organization unique keys and its values. */
  public ConcurrentMap<String, Organization> organizationMap;
  /** contains the researcher unique keys and its values. */
  public ConcurrentMap<String, Researcher> researcherMap;
  /** contains the duplicate unique keys and its values. */
  public ConcurrentMap<String, Object> dublicateMap;

   /** Need to satisfy Pmd. */
  public final String dir = "user.dir";

  /** Changes in class Edit */
  private MyIsernXmlLoader xmlLoader_main;
  /** index of edited researcher */
  public int index;
  /** default loader*/
  private MyIsernXmlLoader xmlLoader;

  /**
   * Private constructor used to create a single instance of myisern.
   */
  public MyIsernModel() {
    try {
      xmlLoader = new MyIsernXmlLoader();
      collaborationMap = new ConcurrentHashMap<String, Collaboration>();
      organizationMap = new ConcurrentHashMap<String, Organization>();
      researcherMap = new ConcurrentHashMap<String, Researcher>();
      dublicateMap = new ConcurrentHashMap<String, Object>();
      // create unique id mappings
      parseXmlCreateMap();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  	try {
  		xmlLoader_main = new MyIsernXmlLoader();
  		collaborationMap = new ConcurrentHashMap<String, Collaboration>();
  	  organizationMap = new ConcurrentHashMap<String, Organization>();
  	  researcherMap = new ConcurrentHashMap<String, Researcher>();
  	  dublicateMap = new ConcurrentHashMap<String, Object>();
  	  //create unique id mappings
  	  parseXmlCreateMap();
  	} catch (Exception e) {
  	  logger.log(Level.SEVERE, e.toString());
  	}
  }
  /**
   * Gets the User Manager.
   * @return the user manager object.
   */
  public UserManager getUserManager() {
    return this.userManager;
  }
  /**
   * Get the single instance of MyIsernModel object.
   *
   * @return A MyIsernModel.
   */
  /**
   * Get the single instance of MyIsernModel object.
   * 
   * @return A MyIsernModel.
   */
  public static synchronized MyIsernModel getInstance() {
    return MyIsernModel.theInstance;
  }

  /**
   * Parse the Xml files.
   */
  private void parseXmlCreateMap() {
    String uniqueId = "";
    for (Organization org : xmlLoader_main.organizations.getOrganization()) {
      uniqueId = org.getName().replace(' ', '_');
      if (organizationMap.containsKey(uniqueId)) {
        dublicateMap.put(uniqueId, org);
      }
      else {
        organizationMap.put(uniqueId, org);
      }
    }
    for (Researcher researcher : xmlLoader_main.researchers.getResearcher()) {
      uniqueId = researcher.getName().replace(' ', '_');
      if (researcherMap.containsKey(uniqueId)) {
        dublicateMap.put(uniqueId, researcher);
      }
      else {
        researcherMap.put(uniqueId, researcher);
      }
    }
    for (Collaboration collab : xmlLoader_main.collaborations.getCollaboration()) {
      uniqueId = collab.getName().replace(' ', '_');
      if (collaborationMap.containsKey(uniqueId)) {
        dublicateMap.put(uniqueId, collab);
      }
      else {
        collaborationMap.put(uniqueId, collab);
      }
    }
  }

  /**
   * Gets the list of errors.
   * 
   * @return The report iterator.
   * @throws Exception
   *                 if there an error.
   */
  public Iterator<SanityCheckErrorItem> getReportIterator() throws Exception {
    SanityCheck sanityCheck = new SanityCheck(this.collaborationMap,
        this.organizationMap, this.researcherMap);
    sanityCheck.verifyResearchers();
    sanityCheck.verifyOrganizations();
    sanityCheck.verifyCollaborations();
    return sanityCheck.getReport().iterator();
  }

  /**
   * Method to check correct information for log in.
   * 
   * @param login   The login name.
   * @param password The login password.
   * @return isValid Returns the boolean value depending if correct login or not
   * @throws Exception  if something wrong.
   */
  /*
  public synchronized boolean checkLogin(String login, String password)
      throws Exception {
    boolean isValid = false;

    if (this.login.equals(login) && this.password.equals(password)) {
      isValid = true;
    }

    return isValid;
  }
*/
  /**
   * A handler that performs the action when the 'save' button is pressed.
   * @param researcherName     Researcher's name
   * @param researcherOrganization   Researcher's organization
   * @param email         Researcher's email
   * @param pictureLink   Researcher's picture link
   * @param bioStatement  Researcher's bio-statement
   * @throws Exception If an error occurs
   */
  public synchronized void saveResearcher(String researcherName,
      String researcherOrganization, String email, String pictureLink,
      String bioStatement) throws Exception {
    String resXmlPath = System.getProperty(home)
        + "/.myisern/researchers.xml";

    MyIsernXmlLoader xmlLoader = new MyIsernXmlLoader();
    Researcher newResearcher = new Researcher();
    newResearcher.setName(researcherName);
    newResearcher.setOrganization(researcherOrganization);
    newResearcher.setEmail(email);
    newResearcher.setPictureLink(pictureLink);
    newResearcher.setBioStatement(bioStatement);
    xmlLoader.researchers.getResearcher().add(newResearcher);
    xmlLoader.marshallResearchers(resXmlPath);
    theInstance = new MyIsernModel();
  }

  /**
   * A handler that performs the action when the 'save' button is pressed.
   * @param organizationName    Organization name
   * @param organizationType    Organization type
   * @param contact             Organization contact
   * @param affiliatedResearcher   Organization Affiliated Researcher
   * @param country        Organization country
   * @param researchKeywords   Organization keywords
   * @param researchDescription    Organization research description
   * @param homePage  Organization home page
   * @throws Exception If an error occurs.
   */
  public synchronized void saveOrganization(String organizationName,
      String organizationType, String contact, String affiliatedResearcher,
      String country, String researchKeywords, String researchDescription,
      String homePage) throws Exception {
    String orgXmlPath = System.getProperty(home)
        + "/.myisern/organizations.xml";

    MyIsernXmlLoader xmlLoader = new MyIsernXmlLoader();
    Organization newOrganization = new Organization();
    AffiliatedResearchers newAffiliatedResearchers = new AffiliatedResearchers();
    ResearchKeywords newKeyword = new ResearchKeywords();

    newOrganization.setName(organizationName);
    newOrganization.setType(organizationType);
    newOrganization.setContact(contact);

    int i = 0;
    String oneAffResearcher = "";
    Character character = ' ';

    while (i != affiliatedResearcher.length()) {
      character = affiliatedResearcher.charAt(i);
      if (character == ',') {
        newAffiliatedResearchers.getAffiliatedResearcher().add(
            oneAffResearcher.trim());
        oneAffResearcher = "";
      }
      else {
        oneAffResearcher = oneAffResearcher.concat(character.toString());
      }
      i++;
    }
    if (oneAffResearcher != "") {
      newAffiliatedResearchers.getAffiliatedResearcher().add(
          oneAffResearcher.trim());
    } 
    newOrganization.setAffiliatedResearchers(newAffiliatedResearchers);    
    newOrganization.setCountry(country);
    

    i = 0;
    String oneResearchKeyword = "";
    character = ' ';
   
    while (i != researchKeywords.length()) {
      character = researchKeywords.charAt(i);
      if (character == ',') {
        newKeyword.getResearchKeyword().add(oneResearchKeyword.trim());
        oneResearchKeyword = "";
      }
      else {
        oneResearchKeyword = oneResearchKeyword.concat(character.toString());
      }
      i++;
    }
    if (oneResearchKeyword != "") {
      newKeyword.getResearchKeyword().add(oneResearchKeyword.trim());
    }
    newOrganization.setResearchKeywords(newKeyword);
    newOrganization.setResearchDescription(researchDescription);
    newOrganization.setHomePage(homePage);

    xmlLoader.organizations.getOrganization().add(newOrganization);
    xmlLoader.marshallOrganizations(orgXmlPath);
    theInstance = new MyIsernModel();
  }

 
  /**
   * A handler that performs the action when the 'save' button is pressed.
   * @param collaborationName    Collaboration name
   * @param collaboratingOrganizations  Collaborating organization
   * @param collaborationTypes  Collaboration type
   * @param year          Collaboration year
   * @param outComeTypes  Collaboration out-come type
   * @param description  Decription of collaboration
   * @throws Exception If an error occurs
   */

  public synchronized void saveCollaboration(String collaborationName,
      String collaboratingOrganizations, String collaborationTypes,
      String year, String outComeTypes, String description) throws Exception {

    String colXmlPath = System.getProperty(home)
        + "/.myisern/collaborations.xml";

    MyIsernXmlLoader xmlLoader = new MyIsernXmlLoader();
    Collaboration newCollaboration = new Collaboration();
    CollaboratingOrganizations collaOrganizations = new CollaboratingOrganizations();
    CollaborationTypes newTypes = new CollaborationTypes();
    Years years = new Years();
    OutcomeTypes newOutcomes = new OutcomeTypes();

    newCollaboration.setName(collaborationName);
    
    int i = 0;
    String oneCollaboratingOrganizations = "";
    Character character = ' ';
   
    while (i != collaboratingOrganizations.length()) {
      character = collaboratingOrganizations.charAt(i);
      if (character == ',') {
        collaOrganizations.getCollaboratingOrganization().add(oneCollaboratingOrganizations.trim());
        oneCollaboratingOrganizations = "";
      }
      else {
        oneCollaboratingOrganizations = oneCollaboratingOrganizations.concat(character.toString());
      }
      i++;
    }
    if (oneCollaboratingOrganizations != "") {
      collaOrganizations.getCollaboratingOrganization().add(oneCollaboratingOrganizations.trim());
    }
    newCollaboration.setCollaboratingOrganizations(collaOrganizations);
    
    
    i = 0;
    String oneCollaborationTypes = "";
    character = ' ';
   
    while (i != collaborationTypes.length()) {
      character = collaborationTypes.charAt(i);
      if (character == ',') {
        newTypes.getCollaborationType().add(oneCollaborationTypes.trim());
        oneCollaborationTypes = "";
      }
      else {
        oneCollaborationTypes = oneCollaborationTypes.concat(character.toString());
      }
      i++;
    }
    if (oneCollaborationTypes != "") {
      newTypes.getCollaborationType().add(oneCollaborationTypes.trim());
    }
    newCollaboration.setCollaborationTypes(newTypes);
    
    i = 0;
    String oneYear = "";
    character = ' ';
   
    while (i != year.length()) {
      character = year.charAt(i);
      if (character == ',') {
        BigInteger bigInteger = new BigInteger(oneYear.trim());
        years.getYear().add(bigInteger);
        oneYear = "";
      }
      else {
        oneYear = oneYear.concat(character.toString());
      }
      i++;
    }
    if (oneYear != "") {
      BigInteger bigInteger = new BigInteger(oneYear.trim());
      years.getYear().add(bigInteger);
    }
    
    newCollaboration.setYears(years);
     
    i = 0;
    String oneType = "";
    character = ' ';
   
    while (i != outComeTypes.length()) {
      character = outComeTypes.charAt(i);
      if (character == ',') {
        newOutcomes.getOutcomeType().add(oneType.trim());
        oneType = "";
      }
      else {
        oneType = oneType.concat(character.toString());
      }
      i++;
    }
    if (oneType != "") {
      newOutcomes.getOutcomeType().add(oneType.trim());
    }  
    newCollaboration.setOutcomeTypes(newOutcomes);
    
    if (description == null) {
      newCollaboration.setDescription("");
    }
    else {
      newCollaboration.setDescription(description);
    }

    xmlLoader.collaborations.getCollaboration().add(newCollaboration);
    xmlLoader.marshallCollaborations(colXmlPath);
    theInstance = new MyIsernModel();
  }

  /**
   * Provides a List containing all the researchers.
   * 
   * @return List containing all researchers.
   * @throws Exception If an error occurs.
   */
  public synchronized List<Researcher> getResearcher() throws Exception {
    // xmlLoader = new MyIsernXmlLoader();
    return xmlLoader_main.researchers.getResearcher();
  }

  /**
   * Provides a List containing all collaborations.
   * 
   * @return List containing all collaborations.
   * @throws Exception If an error occurs.
   */
  public synchronized List<Collaboration> getCollaboration() throws Exception {
    return xmlLoader_main.collaborations.getCollaboration();
  }

  /**
   * Provides a List containing all Organizations.
   * 
   * @return List containing all Organizations.
   * @throws Exception If error occurs.
   */
  public synchronized List<Organization> getOrganization() throws Exception {
    return xmlLoader_main.organizations.getOrganization();
  }
  
  /**
   * Finds the researcher.
   * 
   * @param resName unique id to find
   * @return true if found, false otherwise.
   */
  public synchronized String findResearcher(String resName) {
    String uniqueId = resName.replace(' ', '_');
    if (this.researcherMap.containsKey(uniqueId)) {
      return uniqueId;
    }
    return "";
  }
  
  /**
   * Finds the organization.
   * 
   * @param orgName unique id to find
   * @return true if found, false otherwise
   */
  public synchronized String findOrganization(String orgName) {
    String uniqueId = orgName.replace(' ', '_');
    if (this.organizationMap.containsKey(uniqueId)) {
      return uniqueId;
    }
    return "";
  }
  
  /**
   * Finds the collaboration.
   * 
   * @param colName unique id to find
   * @return true if found, false otherwise
   */
  public synchronized String findCollaboration(String colName) {
    String uniqueId = colName.replace(' ', '_');
    if (this.collaborationMap.containsKey(uniqueId)) {
      return uniqueId;
    }
    return "";    
  }
  
  /**
   * Marshalls the edited researcher object.
   * 
   * @param editResearcher the edited researcher
   * @throws Exception if error occurs
   */
  public synchronized void saveEditedResearcher(Researcher editResearcher) throws Exception {
    String resXmlPath = System.getProperty(home)
    + "/.myisern/researchers.xml";
    
    xmlLoader.researchers.getResearcher().set(this.index, editResearcher);
    xmlLoader.marshallResearchers(resXmlPath);
    theInstance = new MyIsernModel();   
  }
}
